# coding:utf8
"""
    Receive E-mail. ->
        1. poplib  - > get mail
        2.
        3.
"""
import poplib, time
from email.parser import Parser  # 用来解析邮件主题
from email.header import decode_header  # 用来解析邮件header对象
from email.utils import parseaddr  # 用来解析邮件来源

__all__ = ['ReceiveMail', 'dic']


class ReceiveMail:
    """功能：接收并处理邮件
    实例化时必须指定： pop_host, user, passwd
    通过get_mail_quantity 获得邮箱中邮件的数量；
    可以通过get_all_mail, get_one_mail, get_new_mail得到邮件的 标题，发件人，内容；
    """

    def __init__(self, pop_host, user, passwd, **kwargs):
        self.pop_host = pop_host
        self.user = user
        self.passwd = passwd
        self.kwargs = kwargs
        self._debugging = 0

        self.mailServer = poplib.POP3(self.pop_host)
        self.mailServer.set_debuglevel(self._debugging)
        self._mail_login()

    def _mail_login(self):
        self.mailServer.user(self.user)
        self.mailServer.pass_(self.passwd)

    def get_mail_list(self):
        """获取邮件列表"""
        m_num, m_size = self.mailServer.stat()
        print(m_num, m_size)
        _mail_list = self.mailServer.list()
        if _mail_list[0] == b'+OK': return self.mailServer.list()[1]
        else:
            print('Get mail list Error!')
            return 'Error'

    def query_del(self):
        """ 目前dele 无法正常删除 ... """
        all_mail = self.get_all_mail()
        for i in range(0, len(all_mail)): print(i+1, ':', all_mail[i][0])
        for i in range(3, 0, -1):
            try:
                self.mailServer.dele(int(input("你要删除那一封？")))
                break
            except: print("你的输入有误，请重新输入：")

    def del_all_mail(self):
        """ 目前dele 无法正常删除 ... """
        for which in range(1, self.get_mail_quantity()+1):
            self.mailServer.dele(which)

    def get_all_mail(self):
        """获取邮箱中的全部邮件，返回一个列表
        列表中包含全部邮件的元组，(标题，发件地址，内容)
        :return: [,(Subject, senderAddress, content),]
        """
        all_mail = []
        for i in range(1, self.get_mail_quantity()+1):
            all_mail.append(self.get_one_mail(i))
        return all_mail

    def get_new_mail(self):
        """获取最新的一封邮件。
        :return: 一个元组，标题，发件人，内容。
        """
        return self.get_one_mail(self.get_mail_quantity())

    def get_one_mail(self, which):
        """获取一封邮件"""
        _mail = self.mailServer.retr(which)
        if not _mail[0] == b'+OK': return 'Error'
        _mail = b'\r\n'.join(_mail[1]).decode('utf8')
        _mail = Parser().parsestr(text=_mail)
        # print('_mail type is', type(_mail))
        return self._get_mail_title(_mail), self._get_mail_render(_mail), self._get_mail_body(_mail)

    @staticmethod
    def _get_mail_title(msg):
        subject = msg['Subject']
        subject, charset = decode_header(subject)[0]
        if charset: subject = subject.decode(charset)
        return subject

    @staticmethod
    def _get_mail_render(msg):
        addr = parseaddr((msg['From']))[1]
        # hdr, addr = parseaddr(msg['From'])
        # name, charset = decode_header(hdr)[0]
        # if charset: name = name.decode(charset)
        return addr

    @staticmethod
    def _get_mail_body(msg):
        try:
            body = msg.get_payload(decode=True)
            body_charset = msg.get_content_charset()
            return body.decode(body_charset)
        except AttributeError:
            return "此邮件有附件, 脚本无法解码"

    def __del__(self):
        self.mailServer.close()

    def get_mail_quantity(self):
        """返回邮箱中已存在的邮件数量"""
        return self.mailServer.stat()[0]

    def set_debuglevel(self, level):
        self._debugging = level


def get_new_mail(_dic, second=5):
    t = ReceiveMail(**_dic)
    now_count = t.get_mail_quantity()
    print('开启的时候的邮件数量为:%s' % now_count)
    # 每次需要重新连接邮箱服务器，才能获取到最新的消息
    # 默认每隔5秒看一次是否有新内容
    while True:
        obj = ReceiveMail(**_dic)
        count = obj.get_mail_quantity()
        if count > now_count:
            new_mail_count = count - now_count
            print('有新的邮件数量:%s' % new_mail_count)
            for i in range(1, new_mail_count + 1):
                obj = ReceiveMail(**_dic)
                now_count += 1
                mail = obj.get_one_mail(now_count)

                yield {"title": mail[0], "sender_email": mail[1], "email_content": mail[2]}
                # print('-' * 30)
                # print("邮件主题:%s\n发件人:%s\n发件人邮箱:%s\n邮件内容:%s" % (
                #     obj.email_title, obj.sender_qq_name, obj.sender_qq_email, obj.email_content))
                # print('-' * 30)

        # else:
        #     print('没有任何新消息.')

        time.sleep(second)


def main():
    dic = {'pop_host': 'pop.qq.com',
           'smtp_host': 'smtp.qq.com',
           'user': ' 1491311784@qq.com',
           'passwd': ' fxvvlznnwkclheic',
            }
    print('正在监听邮件服务器端是否有新消息---')
    try:
        iterator = get_new_mail(dic)  # 创建了一个可迭代的对象 -> iterator
    except TypeError and AttributeError:
        print('监听的内容有误，有图片数据等,无法解析而报错，不是纯文本内容')
    else:
        for _dic in iterator:
            # 如果需要过滤某个用户的邮件内容，加个if判断是否是该邮箱即可
            # if dic.get("sender_email") == 'xxx':
            print('-' * 30)
            print("邮件主题:%s\n发件人邮箱:%s\n邮件内容:%s" % (
                _dic["title"], _dic["sender_email"], _dic["email_content"]))
            print('-' * 30)


if __name__ == '__main__':
    main()
